//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Microsoft.Research.DataLayer;

namespace Microsoft.Research.DataLayer
{
    public partial class JobRunner : Form
    {
        public delegate void LoadDataProduct(DataProduct[] dpList);
        public event LoadDataProduct OnLoadDataProduct;

        Activity selectedWorkflow = null;
        Job runingJob = null;
        Connection conn;
        string defaultJobName;

        public JobRunner(Control parent, Connection c, string defaultJobName)
        {
            this.conn = c;
            this.defaultJobName = defaultJobName;
            InitializeComponent();
            this.Parent = parent;
        }

        public void Run()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
            {
                Application.Run(this);
            }));
        }

        private void cancel_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void run_Click(object sender, EventArgs e)
        {
            workflowList.Enabled = false;
            run.Enabled = false;
            stop.Enabled = true;
            progressBar1.Visible = true;

            this.Size = new Size(991, 509);

            selectedWorkflow = workflowList.SelectedItems[0].Tag as Activity;

            //
            // Create a new job for the selected workflow
            //
            runingJob = Job.Create(wfName.Text, false, conn);
            runingJob.Status = JobStatus.Initializing;

            ActivityInstance wfInstance = ActivityInstance.Create(selectedWorkflow, conn);

            runingJob.ActivityInstances.Add(wfInstance);

            Machine node = machine.SelectedItem as Machine;
            if (node != null)
                runingJob.Machines.Add(node);

            // Let job run free
            runingJob.Status = JobStatus.Waiting;

            // Let's monitor the job
            monitorWorkflow.Enabled = true;
        }

        private void JobRunner_Load(object sender, EventArgs e)
        {
            wfName.Text = defaultJobName;

            try
            {
                // Initial size (small)
                this.Size = new Size(525, 509);

                workflowList.Items.Clear();

                Collection<Activity> allWorkflows = Activity.CommonSearches.GetAllWorkflows(conn, null);

                foreach (Activity wf in allWorkflows)
                {
                    ListViewItem lvi = new ListViewItem();
                    lvi.ImageIndex = 0;
                    lvi.SubItems.Add(wf.Name);
                    lvi.SubItems.Add(string.Format("{0} {1}",
                        wf.Updated.When.ToShortDateString(),
                        wf.Updated.When.ToShortTimeString()));
                    lvi.Tag = wf;

                    workflowList.Items.Add(lvi);
                }
            }
            catch (RecordNotFoundException)
            {
                // No workflows in the system
            }

            try
            {
                List<Machine> allMachines = Machine.LoadAll(conn);

                machine.Items.Clear();
                machine.Items.AddRange(allMachines.ToArray());
            }
            catch (RecordNotFoundException)
            {
                // No machines to load
            }
        }

        private void workflowList_SelectedIndexChanged(object sender, EventArgs e)
        {
            run.Enabled = (workflowList.SelectedIndices.Count == 1);
        }

        private List<Control> BlinkingControls
        {
            get
            {
                List<Control> controls = new List<Control>();
                controls.Add(jbName);
                controls.Add(jbStart);
                controls.Add(jbStop);
                controls.Add(jbStatus);
                controls.Add(dpCount);
                controls.Add(dpList);
                return controls;
            }
        }

        private void monitorWorkflow_Tick(object sender, EventArgs e)
        {
            runingJob.Refresh();

            List<Control> controls = BlinkingControls;

            if (jbName.Text != runingJob.Name)
            {
                jbName.Text = runingJob.Name;
                jbName.BackColor = Color.Yellow;
                controls.Remove(jbName);
            }

            string startTime = runingJob.StartTime == DateTime.MinValue ? "" : runingJob.StartTime.ToString();
            if (jbStart.Text != startTime)
            {
                jbStart.Text = startTime;
                jbStart.BackColor = Color.Yellow;
                controls.Remove(jbStart);
            }

            string stopTime = runingJob.StopTime == DateTime.MinValue ? "" : runingJob.StopTime.ToString();
            if (jbStop.Text != stopTime)
            {
                jbStop.Text = stopTime;
                jbStop.BackColor = Color.Yellow;
                controls.Remove(jbStop);
            }

            if (jbStatus.Text != runingJob.Status.ToString())
            {
                jbStatus.Text = runingJob.Status.ToString();
                jbStatus.BackColor = Color.Yellow;
                controls.Remove(jbStatus);
            }

            int count = runingJob.ActivityInstances[0].Outputs.Count;
            if (dpCount.Text != count.ToString())
            {
                dpCount.Text = count.ToString();
                dpCount.BackColor = Color.Yellow;

                dpList.Items.Clear();
                if (count > 0)
                {
                    foreach (DataProduct dp in runingJob.ActivityInstances[0].Outputs)
                    {
                        ListViewItem lvi = new ListViewItem();
                        lvi.ImageIndex = 0;
                        lvi.SubItems.Add(dp.Name);
                        lvi.SubItems.Add(dp.Type);
                        lvi.Tag = dp;

                        dpList.Items.Add(lvi);
                    }
                }
                dpList.BackColor = Color.Yellow;

                controls.Remove(dpCount);
                controls.Remove(dpList);
            }

            foreach (Control c in controls)
            {
                if (c == dpList)
                    c.BackColor = SystemColors.Window;
                else
                    c.BackColor = c.Parent.BackColor;
            }

            switch (runingJob.Status)
            {
                case JobStatus.Completed:
                case JobStatus.Aborted:
                    StopJobMonitor();
                    break;

                default:
                    break;
            }
        }

        private void StopJobMonitor()
        {
            monitorWorkflow.Enabled = false;
            run.Enabled = true;
            stop.Enabled = false;
            progressBar1.Visible = false;

            List<Control> controls = BlinkingControls;
            foreach (Control c in controls)
            {
                if (c == dpList)
                    c.BackColor = SystemColors.Window;
                else
                    c.BackColor = c.Parent.BackColor;
            }

            resultIcon.Image = runingJob.Success && (runingJob.Status == JobStatus.Completed) ?
                Properties.Resource1.ok.ToBitmap() :
                Properties.Resource1.error.ToBitmap();
        }

        private void dpList_SelectedIndexChanged(object sender, EventArgs e)
        {
            loadDP.Enabled = (dpList.SelectedIndices.Count > 0);
        }

        private void stop_Click(object sender, EventArgs e)
        {
            runingJob.Refresh();

            switch (runingJob.Status)
            {
                case JobStatus.Aborted:
                case JobStatus.Completed:
                    break;
                default:
                    runingJob.Status = JobStatus.StopPending;
                    break;
            }
        }

        private void loadDP_Click(object sender, EventArgs e)
        {
            if (OnLoadDataProduct != null)
            {
                try
                {
                    loadWait.Visible = true;
                    Cursor = Cursors.WaitCursor;
                    Application.DoEvents();

                    List<DataProduct> retDpList = new List<DataProduct>();

                    foreach (ListViewItem lvi in dpList.SelectedItems)
                    {
                        retDpList.Add(lvi.Tag as DataProduct);
                    }

                    OnLoadDataProduct(retDpList.ToArray());
                }
                finally
                {
                    loadWait.Visible = false;
                    Cursor = Cursors.Default;
                }
            }
        }

        private void machine_Format(object sender, ListControlConvertEventArgs e)
        {
            Machine m = e.ListItem as Machine;

            if( m == null )
                return;

            e.Value = string.Format("{0}{1}", m.Name,
                m.IsInteractiveExecution ? " (Interactive)" : "");
        }
    }
}
